Web pipeline: retrieval rides with discovery; hallucinated fetch calls get steered - #2625
Merged
Conversation
added 2 commits
September 3, 2026 19:49
…s get steered A model with web search enabled used to see only web_search (discovery) in its schema; retrieval (search_and_extract) sat behind a capabilities_load round-trip. Observed live: models loop-rephrased web_search or hallucinated web_fetch — a tool that has never existed here — and produced zero page reads. - search_and_extract is now composed into the schema whenever web search is enabled (was: Charts+Web combo or orchestrator only). The web-off strip still removes both halves. - web_search's description names the direct transition and says plainly that search_and_extract IS the fetch tool; the capabilities_load detour is gone (on the Default agent that loader is gated to configure writes, so following the old text produced a rejected load). Same fix in the web_search anti-loop nudge. - Calls to fetch-tool names imported from other harnesses (web_fetch, fetch_url, read_webpage, ...) return a retryable envelope steering to search_and_extract — only when the name has no real registration (a plugin/MCP tool claiming it always wins), the request's scope already exposes search_and_extract (nothing withheld is leaked; HTTP/MCP surfaces with nil scope keep the generic refusal), and no plugin group shares the name (the group-load rescue keeps precedence). Browser-intent (browse, open_url) and shell-intent (curl) names are deliberately not steered. - Tests: composer exposure both ways, steering + opacity contracts, and the superseded lean-baseline pin updated.
…te test additions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A model with web search enabled saw only
web_search(discovery) in its schema; retrieval (search_and_extract) sat behind acapabilities_loadround-trip. Observed live: models loop-rephrasedweb_searchor hallucinatedweb_fetch— a tool that has never existed in osaurus — and produced zero page reads (the Raptor research-run failure).What
search_and_extractis composed into the schema whenever web search is enabled (was: Charts+Web combo or orchestrator only). The web-off strip still removes both halves; manual mode untouched. Cost: ~350–420 tokens on web-enabled prompts — the same spec the Charts+Web path already paid.web_search's description names the direct transition ("search_and_extract IS the fetch tool") and drops thecapabilities_loaddetour — on the Default agent that loader is gated to configure writes, so the old text steered into a rejected load. Same fix in the web_search anti-loop nudge.web_fetch/fetch_url/read_webpage/… return a retryable envelope pointing atsearch_and_extract— only when the name has no real registration (a plugin/MCP tool claiming it always wins), the request's scope already exposessearch_and_extract(nothing withheld is leaked; nil-scope HTTP/MCP surfaces keep the generic refusal), and no plugin group shares the name (group-load rescue keeps precedence). Browser-intent (browse,open_url) and shell-intent (curl) names are deliberately excluded.Verification
toolsByNameguard keeps real registrations winning; group rescue precedence guarded; envelope keys verified againstToolEnvelope.failure.